package com.ruoyi.business.service;

import com.ruoyi.business.domain.EquipmentVariables;
import com.ruoyi.business.domain.S7VariablesConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * S7变量管理服务
 * 负责管理S7协议变量配置，在项目启动时自动加载激活的变量
 *
 * @author qiancheng
 * @date 2025-08-30
 */
@Service
@Order(1) // 确保优先执行，为后续连接管理服务提供变量配置
public class S7VariableManagerService implements ApplicationRunner {

    private static final Logger log = LoggerFactory.getLogger(S7VariableManagerService.class);

    @Autowired
    private IS7VariablesConfigService s7VariablesConfigService;

    @Autowired
    private IEquipmentVariablesService equipmentVariablesService;

    /**
     * 按PLC IP分组的变量配置缓存
     * Key: PLC IP地址
     * Value: 该PLC下的所有激活变量列表
     */
    private final Map<String, List<S7VariablesConfig>> plcVariablesCache = new ConcurrentHashMap<>();

    /**
     * 按变量英文名称索引的变量配置缓存
     * Key: 变量英文名称
     * Value: 变量配置对象
     */
    private final Map<String, S7VariablesConfig> variableNameCache = new ConcurrentHashMap<>();

    /**
     * EquipmentVariables映射缓存
     * Key: 变量英文名称
     * Value: EquipmentVariables对象
     */
    private final Map<String, EquipmentVariables> equipmentVariablesCache = new ConcurrentHashMap<>();

    /**
     * 警报plc信息缓存
     * Key: 英文名称 固定字符
     * Value: S7VariablesConfig
     */
    private final Map<String, S7VariablesConfig> alarmS7MapCache = new ConcurrentHashMap<>();

    /**
     * 报警状态缓存
     * Key: 变量英文名称
     * Value: 上一次采集值（true/false）
     */
    private final Map<String, Boolean> alarmStatusCache = new ConcurrentHashMap<>();


    /**
     * 项目启动后自动执行，加载所有激活的S7变量配置
     */
    //@Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("======= 开始加载S7变量配置 =======");

        try {
            // 查询所有激活的S7变量配置
            S7VariablesConfig queryConfig = new S7VariablesConfig();
            queryConfig.setIsActive("1"); // 只查询激活状态的变量

            List<S7VariablesConfig> activeVariables = s7VariablesConfigService.selectS7VariablesConfigList(queryConfig);


            if (activeVariables == null || activeVariables.isEmpty()) {
                log.warn("未找到激活的S7变量配置");
                return;
            }

            // 按PLC IP地址分组
            Map<String, List<S7VariablesConfig>> groupedByPlcIp = activeVariables.stream()
                    //.filter(var -> !(var.getRemark() != null && var.getRemark().trim().equalsIgnoreCase("alarm"))) // 过滤alarm
                    .collect(Collectors.groupingBy(S7VariablesConfig::getPlcIp));

            // 警报PLC
            // 先过滤出remark为"alarm"的记录，再按variableEnName分组
            // 过滤出remark为"alarm"的记录，并按variableEnName映射为单值Map
            Map<String, S7VariablesConfig> alarmVariablesMap = activeVariables.stream()
                    // 过滤条件：remark为"alarm"（忽略大小写和空格）
                    .filter(var -> var.getRemark() != null && var.getRemark().trim().equalsIgnoreCase("alarm"))
                    // 收集为Map，键为variableEnName，值为对应的S7VariablesConfig对象
                    .collect(Collectors.toMap(
                            S7VariablesConfig::getVariableEnName,  // 键：variableEnName
                            Function.identity(),                  // 值：对象本身
                            (existing, replacement) -> existing   // 若出现重复的variableEnName，保留第一个
                    ));

            // 更新PLC变量缓存
            plcVariablesCache.clear();
            plcVariablesCache.putAll(groupedByPlcIp);
            //警报
            alarmS7MapCache.putAll(alarmVariablesMap);
        // 初始化报警状态缓存（全部置为false，表示初始无报警）
            alarmStatusCache.clear();
            alarmS7MapCache.keySet().forEach(varName -> alarmStatusCache.put(varName, Boolean.FALSE));

            // 按变量英文名称建立索引
            variableNameCache.clear();
            for (S7VariablesConfig variable : activeVariables) {
                if (variable.getVariableEnName() != null && !variable.getVariableEnName().trim().isEmpty()) {
                    variableNameCache.put(variable.getVariableEnName(), variable);
                }
            }

            // 加载并缓存EquipmentVariables数据
            loadAndCacheEquipmentVariables();

            // 输出加载统计信息
            log.info("S7变量配置加载完成:");
            log.info("- 总共加载激活变量: {} 个", activeVariables.size());
            log.info("- 涉及PLC设备数量: {} 台", plcVariablesCache.size());
            log.info("- EquipmentVariables映射数量: {} 个", equipmentVariablesCache.size());
            log.info("- 警报映射数量: {} 个", alarmS7MapCache.size());

            // 输出每个PLC的变量统计
            plcVariablesCache.forEach((plcIp, variables) -> {
                log.info("- PLC [{}]: {} 个变量", plcIp, variables.size());
            });

        } catch (Exception e) {
            log.error("加载S7变量配置失败", e);
            throw e;
        }

        log.info("======= S7变量配置加载完成 =======");
    }

    /**
     * 获取指定PLC的所有激活变量
     *
     * @param plcIp PLC IP地址
     * @return 变量配置列表
     */
    public List<S7VariablesConfig> getVariablesByPlcIp(String plcIp) {
        return plcVariablesCache.get(plcIp);
    }

    /**
     * 获取所有PLC IP列表
     *
     * @return PLC IP地址列表
     */
    public List<String> getAllPlcIps() {
        return plcVariablesCache.keySet().stream().collect(Collectors.toList());
    }

    /**
     * 获取所有警报PLC
     *
     * @return PLC
     */
    public Map<String, S7VariablesConfig> getAlarmS7MapCache() {
        return alarmS7MapCache;
    }

    /**
     * 获取所有警报PLC状态缓存
     *
     * @return PLC
     */
    public Map<String, Boolean> getAlarmS7StatusMap() {
        return alarmStatusCache;
    }

    /**
     * 根据变量英文名称获取变量配置
     *
     * @param variableEnName 变量英文名称
     * @return 变量配置对象
     */
    public S7VariablesConfig getVariableByEnName(String variableEnName) {
        return variableNameCache.get(variableEnName);
    }

    /**
     * 获取所有激活变量的数量
     *
     * @return 激活变量总数
     */
    public int getTotalActiveVariablesCount() {
        return variableNameCache.size();
    }

    /**
     * 获取PLC设备数量
     *
     * @return PLC设备数量
     */
    public int getPlcDeviceCount() {
        return plcVariablesCache.size();
    }

    /**
     * 重新加载变量配置（用于配置变更后的热更新）
     */
    public synchronized void reloadVariables() {
        log.info("开始重新加载S7变量配置...");
        try {
            run(null);
            log.info("S7变量配置重新加载成功");
        } catch (Exception e) {
            log.error("重新加载S7变量配置失败", e);
        }
    }

    /**
     * 检查指定PLC是否有激活的变量配置
     *
     * @param plcIp PLC IP地址
     * @return true-有激活变量，false-无激活变量
     */
    public boolean hasActiveVariables(String plcIp) {
        List<S7VariablesConfig> variables = plcVariablesCache.get(plcIp);
        return variables != null && !variables.isEmpty();
    }

    /**
     * 获取缓存的统计信息
     *
     * @return 统计信息映射
     */
    public Map<String, Object> getCacheStatistics() {
        Map<String, Object> stats = new ConcurrentHashMap<>();
        stats.put("totalActiveVariables", getTotalActiveVariablesCount());
        stats.put("plcDeviceCount", getPlcDeviceCount());
        stats.put("plcIpList", getAllPlcIps());

        // 每个PLC的变量数量统计
        Map<String, Integer> plcVariableCounts = plcVariablesCache.entrySet().stream()
                .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    entry -> entry.getValue().size()
                ));
        stats.put("plcVariableCounts", plcVariableCounts);

        return stats;
    }

    /**
     * 加载并缓存EquipmentVariables数据
     */
    private void loadAndCacheEquipmentVariables() {
        try {
            // 获取所有S7变量的英文名称
            List<String> variableEnNames = new ArrayList<>(variableNameCache.keySet());

            if (!variableEnNames.isEmpty()) {
                // 批量查询EquipmentVariables
                List<EquipmentVariables> equipmentVariables = equipmentVariablesService.selectEquipmentVariablesByEnNames(variableEnNames);

                // 清空缓存并重新建立映射
                equipmentVariablesCache.clear();
                for (EquipmentVariables equipVar : equipmentVariables) {
                    if (equipVar.getVariableEnName() != null) {
                        equipmentVariablesCache.put(equipVar.getVariableEnName(), equipVar);
                    }
                }

                log.info("加载 EquipmentVariables 数据完成，共 {} 个变量", equipmentVariables.size());
            }
        } catch (Exception e) {
            log.error("加载EquipmentVariables数据失败", e);
        }
    }

    /**
     * 获取EquipmentVariables映射
     *
     * @return EquipmentVariables映射
     */
    public Map<String, EquipmentVariables> getEquipmentVariablesCache() {
        return new ConcurrentHashMap<>(equipmentVariablesCache);
    }

    /**
     * 根据变量英文名称获取EquipmentVariables
     *
     * @param variableEnName 变量英文名称
     * @return EquipmentVariables对象
     */
    public EquipmentVariables getEquipmentVariableByEnName(String variableEnName) {
        return equipmentVariablesCache.get(variableEnName);
    }
}
